/**
 * 
 * Copyright (C) 2011 Cody Stoutenburg . All rights reserved.
 *
 *       This program is free software; you can redistribute it and/or
 *       modify it under the terms of the GNU Lesser General Public License
 *       as published by the Free Software Foundation; either version 2.1
 *       of the License, or (at your option) any later version.
 *
 *       This program is distributed in the hope that it will be useful,
 *       but WITHOUT ANY WARRANTY; without even the implied warranty of
 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *       GNU Lesser General Public License for more details.
 *
 *       You should have received a copy of the GNU Lesser General Public License
 *       along with this program; if not, write to the Free Software
 *       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 * 
 */
package ca.usherbrooke.model.entity;

import java.util.List;

import org.newdawn.slick.geom.Rectangle;

import ca.usherbrooke.model.IBaseModel;
import ca.usherbrooke.model.equipment.EquipmentModel;
import ca.usherbrooke.model.equipment.ProtectionModel;
import ca.usherbrooke.model.equipment.WeaponModel;
import ca.usherbrooke.tools.position.Vector2D;

/**
 * @author Cody Stoutenburg
 * 
 */
public interface IEntityModel extends IBaseModel {

	// /////////// vision methods //////////////
	/**
	 * get the rectangle of what the entity can see if nothing block the view
	 * 
	 * @return the rectangle of what see the entity if no problem
	 */
	Rectangle getViewingArea();

	// /////////// jump methods //////////////
	/**
	 * ask the entity to jump
	 */
	void doJump();

	/**
	 * return true if the entity is jumping, else return false;
	 * 
	 * @return true if the entity is currently jumping
	 */
	Boolean isJumping();

	/**
	 * get the time the entity must wait between two jump
	 * 
	 * @return the time the entity must wait between two jump
	 */
	Integer getJumpReloadTime();

	/**
	 * get the remaining time the entity must wait before another jump
	 * 
	 * @return the remaining time the entity must wait before another jump
	 */
	Integer getRemaningJumpReload();

	/**
	 * get the maximum time the entity can be jumping
	 * 
	 * @return the maximum time the entity can be jumping
	 */
	Integer getMaxJumpDuration();

	/**
	 * get the current time the entity is jumping
	 * 
	 * @return the current time the entity is jumping
	 */
	Integer getCurrentJumpDuration();

	// ///////// HP methods ////////////
	/**
	 * get the maximum hp of the entity
	 * 
	 * @return the maximum hp of the entity
	 */
	Integer getMaxHP();

	/**
	 * get the current hp of the entity
	 * 
	 * @return the current hp of the entity
	 */
	Integer getCurrentHP();

	// /////// walk methods ////////
	/**
	 * get the max speed of the entity
	 * 
	 * @return the max speed of the entity
	 */
	Float getMaxSpeed();

	/**
	 * get the current speed of the entity
	 * 
	 * @return the current speed of the entity
	 */
	Vector2D getCurrentSpeed();

	/**
	 * get the current speed of the entity modified by the environment
	 * 
	 * @return the current speed of the entity modified by the environment
	 */
	Vector2D getRealSpeed();

	/**
	 * get the last target position reach by the entity
	 * 
	 * @return the last target position reach by the entity
	 */
	Vector2D getLastTargetReach();

	/**
	 * get the current target position of the entity
	 * 
	 * @return the current target position of the entity
	 */
	Vector2D getTargetPosition();

	/**
	 * set the speed of the entity
	 * 
	 * @param newSpeed
	 *            the new speed of the entity
	 */
	void setSpeed(Vector2D newSpeed);

	/**
	 * set the target position of the entity.<br/>
	 * the target position is reach when the upper left corner of the entity
	 * reach the target position
	 * 
	 * @param upperLeftCorner
	 *            the target position
	 */
	void setTargetPosition(Vector2D upperLeftCorner);

	// Attack methods
	/**
	 * get the current weapon hold by the entity
	 * 
	 * @return the current weapon hold by the entity
	 */
	WeaponModel getCurrentWeapon();

	/**
	 * get all the protection wear by the entity
	 * 
	 * @return all the protection wear by the entity
	 */
	List<ProtectionModel> getCurrentProtection();

	/**
	 * get the remaining time before the next attack
	 * 
	 * @return the remaining time before the next attack
	 */
	Integer getRemainingAttackTime();

	/**
	 * get the defense of the entity
	 * 
	 * @return the defense of the entity
	 */
	Integer getDefense();

	/**
	 * get the attack modifier of the entity
	 * 
	 * @return the attack modifier of the entity
	 */
	Integer getAttackModifier();

	/**
	 * ask the entity to attack an other entity
	 * 
	 * @param defender
	 *            the entity to attack
	 */
	void doAttack(IEntityModel defender);

	/**
	 * the entity take damage
	 * 
	 * @param damage
	 *            the quantity of damage taken by the entity
	 */
	void doDamage(Integer damage);

	/**
	 * get the attack range of the current weapon
	 * 
	 * @return the range of the current weapon
	 */
	Float getRange();

	/**
	 * verify if the entity is dead
	 * 
	 * @return true if the entity is dead
	 */
	Boolean isDead();

	/**
	 * verify if the entity can wear the new protection
	 * 
	 * @param newProtection
	 *            the protection you want to wear
	 * @return true if the entity can wear the protection
	 */
	Boolean canWearProtection(ProtectionModel newProtection);

	/**
	 * verify if the entity presently wear the protection
	 * 
	 * @param protection
	 *            the protection you want to verify
	 * @return true if the entity presently wear the protection
	 */
	Boolean doesWearProtection(ProtectionModel protection);

	/**
	 * take a protection in the equipment and wear it
	 * 
	 * @param protection
	 *            the protection to wear
	 */
	void takeProtection(ProtectionModel protection);

	/**
	 * unequip the protection of the entity and put it back to the equipment
	 * 
	 * @param protection
	 *            the protection to unequip
	 */
	void putDownProtection(ProtectionModel protection);

	/**
	 * verify if the weapon can hold a weapon
	 * 
	 * @param weapon
	 *            the weapon to hold
	 * @return true if the entity can wear the weapon
	 */
	Boolean canTakeWeapon(WeaponModel weapon);

	/**
	 * hold a weapon from the equipment
	 * 
	 * @param weapon
	 *            the weapon to hold
	 */
	void takeWeapon(WeaponModel weapon);

	/**
	 * unequip weapon and put it back to the equipment
	 * 
	 * @param weapon
	 *            the weapon to unequip
	 */
	void putDownWeapon();

	// Equipment
	/**
	 * return true if the entity can pick up the equipment
	 * 
	 * @param newEquipement
	 *            an equipment
	 * @return true if the entity can pick up the equipment
	 */
	Boolean canPickUpEquipment(EquipmentModel newEquipement);

	/**
	 * pick up the equipment only if <code>canPickUpEquipment</code> return true
	 * 
	 * @param equipement
	 *            the equipment to pick up
	 */
	void pickUp(EquipmentModel equipement);

	/**
	 * Put down the equipment at the current position of the entity. <br/>
	 * The equipment should be hold by the entity
	 * 
	 * @param oldEquipement
	 *            the equipment to drop
	 * @return true if the equipment is succefully put down
	 */
	Boolean putDown(EquipmentModel oldEquipement);

	/**
	 * get all equipment hold by the entity
	 * 
	 * @return all equipment hold by the entity
	 */
	List<EquipmentModel> getEquipments();

	/**
	 * get all weapons that are in equipments
	 * 
	 * @return all weapons that are in equipments
	 */
	List<WeaponModel> getWeaponsInEquipments();

	/**
	 * get all protections that are in equipments
	 * 
	 * @return all protections that are in equipments
	 */
	List<ProtectionModel> getProtectionsInEquipments();

	/**
	 * get the current capacity of the entity<br/>
	 * the remain capacity is <code>getMaxCapacity() - getCapacity()</code>
	 * 
	 * @return the current capacity
	 */
	Integer getCapacity();

	/**
	 * get the max capacity of the entity
	 * 
	 * @return the maximum capacity of the entity
	 */
	Integer getMaxCapacity();
}
